﻿using ApiLib.AppStart;
using ApiLib.Models;
using ApiLib.Utils;
using Furion.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace ApiLib.Controllers;

/// <summary>
/// OnlyOffice对接
/// </summary>
[ApiDescriptionSettings(GlobalConstants.ApiDescriptionSettings)]
public class OnlyOfficeController : BaseController
{
    /// <summary>
    /// 查看文件信息
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public SysFileInfo FileInfo(int id)
    {
        var sysFileInfo = Db.Queryable<SysFileInfo>().InSingle(id);
        if (sysFileInfo == null)
        {
            throw ActionException("文件不存在");
        }

        if (sysFileInfo.IsDelete)
        {
            throw ActionException("文件已删除");
        }

        var historyInfos = Db.Queryable<SysFileHistoryInfo>().Where(info => info.FileId == id).ToList() ??
                           new List<SysFileHistoryInfo>();
        /*if (historyInfos.Count == 0)
        {
            var historyInfo = new SysFileHistoryInfo()
            {
                FileId = id,
                Path = sysFileInfo.Path,
                Key = sysFileInfo.Key,
                Version = sysFileInfo.Version,
                CreateTime = LocalTime,
                UserId = sysFileInfo.CreateUser,
                UserName = GetUser(sysFileInfo.CreateUser)?.GetName() ?? "未知"
            };
            var identity = Db.Insertable(historyInfo).ExecuteReturnIdentity();
            historyInfo.Id = identity;
            historyInfos.Add(historyInfo);
        }*/

        sysFileInfo.HistoryInfos = historyInfos;
        return sysFileInfo;
    }

    /// <summary>
    /// only_office回调
    /// </summary>
    /// <param name="callbackData"></param>
    /// <returns></returns>
    [AllowAnonymous, NonUnify]
    public object Callback(CallbackData callbackData)
    {
        //状态监听，参见https://api.onlyoffice.com/cn/editors/callback
        var sysFileInfo = Db.Queryable<SysFileInfo>().First(info => info.Key == callbackData.key);
        if (sysFileInfo == null)
        {
            var historyInfo = Db.Queryable<SysFileHistoryInfo>().First(info => info.Key == callbackData.key);
            if (historyInfo != null)
            {
                sysFileInfo = Db.Queryable<SysFileInfo>().InSingle(historyInfo.FileId);
            }
        }

        if (sysFileInfo == null || sysFileInfo.IsDelete)
        {
            return new { error = 1 };
        }

        switch (callbackData.status)
        {
            case 1:
                //正在编辑文档
                break;
            case 2:
            {
                //文档已准备好保存
                try
                {
                    if (callbackData.url.IsNotNullOrEmpty())
                    {
                        ToSaveFile(callbackData, sysFileInfo); //保存文件
                    }
                }
                catch (Exception e)
                {
                    e.Message.LogError();
                    return new { error = 1 };
                }

                break;
            }
            case 3:
                //发生文档保存错误
                break;
            case 4:
                //文档已关闭，没有任何更改
                break;
            case 6:
                //正在编辑文档，但保存了当前文档状态
                break;
            case 7:
                //强制保存文档时发生错误
                break;
        }

        return new { error = 0 };
    }

    /// <summary>
    /// 保存文件
    /// </summary>
    /// <param name="callbackData"></param>
    /// <param name="sysFileInfo"></param>
    private void ToSaveFile(CallbackData callbackData, SysFileInfo sysFileInfo)
    {
        var verId = int.Parse(sysFileInfo.Version);
        var newVer = verId + 1;
        var newKey = (sysFileInfo.Key.Contains('_') ? sysFileInfo.Key.Split("_")[0] : sysFileInfo.Key) + "_" + newVer;
        var changeUrl = "";

        if (callbackData.changesurl.IsNotNullOrEmpty())
        {
            var changesUrl = callbackData.changesurl.Replace("\\u0026", "&");
            var changes = HttpUtil.Download(changesUrl);
            if (changes != null)
            {
                changeUrl = SaveHistoryFile(changes, sysFileInfo.Path, newVer, ".zip");
            }
        }

        var downloadUrl = callbackData.url.Replace("\\u0026", "&");
        var download = HttpUtil.Download(downloadUrl);
        if (download != null)
        {
            Db.Insertable(new SysFileHistoryInfo()
            {
                FileId = sysFileInfo.Id,
                Path = sysFileInfo.Path,
                Change = changeUrl,
                CreateTime = sysFileInfo.CreateTime,
                UserId = sysFileInfo.UpdateUser,
                Version = sysFileInfo.Version,
                Key = sysFileInfo.Key,
            }).ExecuteCommand();

            var newPath = SaveHistoryFile(download, sysFileInfo.Path, newVer);
            sysFileInfo.Version = newVer.ToString();
            sysFileInfo.Key = newKey;
            sysFileInfo.Path = newPath;
            sysFileInfo.UpdateUser = callbackData.actions[0].userid;
            sysFileInfo.UpdateTime = LocalTime;
            Db.Updateable(sysFileInfo).ExecuteCommand();
        }
    }

    /// <summary>
    /// 保存文件
    /// </summary>
    /// <param name="stream"></param>
    /// <param name="path"></param>
    /// <param name="version"></param>
    /// <param name="ext"></param>
    /// <returns></returns>
    private string SaveHistoryFile(Stream stream, string path, int version, string ext = "")
    {
        if (ext.IsNullOrEmpty())
        {
            ext = Path.GetExtension(path); //后缀名
        }

        var name = path.Contains('_') ? path.Split("_")[0] : path.Split(".")[0];
        var newPath = name + $"_{version}" + ext; //后缀名
        var savePath = Path.Combine(AppContext.BaseDirectory, newPath);
        // 保存到指定路径
        stream.CopyToSave(savePath);
        return newPath;
    }
}

public class CallbackData
{
    //用户与文档的交互状态。0：用户断开与文档共同编辑的连接；1：新用户连接到文档共同编辑；2：用户单击强制保存按钮
    public CallbackDataAction[] actions { get; set; }

    /**
     * 文档变更的历史记录，仅当 status 等于 2 或者 3 时该字段才有值。其中的 serverVersion 字段也是 refreshHistory 方法的入参
     */
    public object history { get; set; }

    /**
     * 文档编辑的元数据信息，用来跟踪显示文档更改记录，仅当 status 等于 2 或者 2 时该字段才有值。该字段也是 setHistoryData（显示与特定文档版本对应的更改，类似 Git 历史记录）方法的入参
     */
    public string changesurl { get; set; }

    /**
     * url 字段下载的文档扩展名，文件类型默认为 OOXML 格式，如果启用了 assemblyFormatAsOrigin（https://api.onlyoffice.com/editors/save#assemblyFormatAsOrigin） 服务器设置则文件以原始格式保存
     */
    public string filetype { get; set; }

    /**
     * 文档强制保存类型。0：对命令服务（https://api.onlyoffice.com/editors/command/forcesave）执行强制保存；1：每次保存完成时都会执行强制保存请求，仅设置 forcesave 等于 true 时生效；2：强制保存请求由计时器使用服务器中的设置执行。该字段仅 status 等于 7 或者 7 时才有值
     */
    public int forcesavetype { get; set; }

    /**
     * 文档标识符，类似 id，在 Onlyoffice 服务内部唯一
     */
    public string key { get; set; }

    /**
     * 文档状态。1：文档编辑中；2：文档已准备好保存；3：文档保存出错；4：文档没有变化无需保存；6：正在编辑文档，但保存了当前文档状态；7：强制保存文档出错
     */
    public int status { get; set; }

    /**
     * 已编辑文档的链接，可以通过它下载到最新的文档，仅当 status 等于 2、3、6 或 7 时该字段才有值
     */
    public string url { get; set; }

    /**
     * 自定义参数，对应指令服务的 userdata 字段
     */
    public object userdata { get; set; }

    /**
     * 打开文档进行编辑的用户标识列表，当文档被修改时，该字段将返回最后编辑文档的用户标识符，当 status 字段等于 2 或者 6 时有值
     */
    public string[] users { get; set; }

    /**
     * 最近保存时间
     */
    public string lastsave { get; set; }

    /**
     * 加密令牌
     */
    public string token { get; set; }
}

/// <summary>
/// 回调的Action
/// </summary>
public class CallbackDataAction
{
    /// <summary>
    /// 
    /// </summary>
    public int type { get; set; }
    /// <summary>
    /// 
    /// </summary>
    public string userid { get; set; }
}